// StereoCorrespond.cpp : main project file.

#include "stdafx.h"
#include "MainWindow.h"
#include "Algorithm.h"

using namespace StereoCorrespond;

[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
	// Enabling Windows XP visual effects before any controls are created
	Application::EnableVisualStyles();
	Application::SetCompatibleTextRenderingDefault(false); 

	// Create the main window and run it
	if (args->Length == 2)
	{
		Application::Run(gcnew MainWindow((String^)args->GetValue(0), (String^)args->GetValue(1)));
	}
	else
	{
		Application::Run(gcnew MainWindow());
	}
	return 0;
}

namespace StereoCorrespond
{
	System::Void MainWindow::MainWindow_Load(System::Object^  sender, System::EventArgs^  e)
	{
		leftPictureViewer->Image = Image::FromFile(LeftFileName);
		rightPictureViewer->Image = Image::FromFile(RightFileName);
		imageUpdated(true, true);
	}

	System::Void MainWindow::imageUpdated(bool left, bool right)
	{
		// set separator
		if(left && right) {
			int width = stereoSplitContainer->ClientSize.Width;
			int left_width = leftPictureViewer->Image->Size.Width;
			int right_width = rightPictureViewer->Image->Size.Width;
			float aspect = (float)left_width / (float)(left_width + right_width);
			stereoSplitContainer->SplitterDistance = (int)(aspect*width);
		}

		// update image
		if(left)
			leftPictureViewer->imageUpdated();
		if(right)
			rightPictureViewer->imageUpdated();
	}

	System::Void MainWindow::openToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		imageOpenFileDialog->Multiselect = true;
		if(System::Windows::Forms::DialogResult::OK == imageOpenFileDialog->ShowDialog())
		{
			if(imageOpenFileDialog->FileNames->Length != 2)
			{
				MessageBox::Show(this, "Two files must be selected!", "Error!",MessageBoxButtons::OK, MessageBoxIcon::Error);
				return;
			}
			
			LeftFileName = (String^)imageOpenFileDialog->FileNames[0];
			RightFileName = (String^)imageOpenFileDialog->FileNames[1];

			leftPictureViewer->Image = Image::FromFile(LeftFileName);
			rightPictureViewer->Image = Image::FromFile(RightFileName);
			imageUpdated(true, true);
		}
	}
	
	System::Void MainWindow::openLeftToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		imageOpenFileDialog->Multiselect = false;
		if(System::Windows::Forms::DialogResult::OK == imageOpenFileDialog->ShowDialog())
		{			
			LeftFileName = (String^)imageOpenFileDialog->FileName;
			leftPictureViewer->Image = Image::FromFile(LeftFileName);
			imageUpdated(true, false);
		}
	}

	System::Void MainWindow::openRightToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		imageOpenFileDialog->Multiselect = false;
		if(System::Windows::Forms::DialogResult::OK == imageOpenFileDialog->ShowDialog())
		{			
			RightFileName = (String^)imageOpenFileDialog->FileName;
			rightPictureViewer->Image = Image::FromFile(RightFileName);
			imageUpdated(false, true);
		}
	}

	System::Void MainWindow::exitToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		Close();
	}
	
	System::Void MainWindow::gaussFilterToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
/*
		if(System::Windows::Forms::DialogResult::OK == gaussWindow.ShowDialog()) {
			Filter^ gauss = Filter::createGauss(gaussWindow.Sigma);
			leftPictureViewer->Image = gauss->Run(gcnew Bitmap(leftPictureViewer->Image));
		}
*/
		if(System::Windows::Forms::DialogResult::OK == gaussWindow.ShowDialog()) {
			Algorithm::Filter<float> gauss = Algorithm::Filter<float>::createGauss(gaussWindow.Sigma); 
			Algorithm::Bitmap<float>* orig = toBitmap_float(gcnew Bitmap(leftPictureViewer->Image));
			Algorithm::Bitmap<float>* result = gauss.Run(*orig);
			leftPictureViewer->Image = toCLRBitmap(result);
			delete result;
			delete orig;
		}

	}
	
	System::Void MainWindow::resetImagesToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		if(LeftFileName)
			leftPictureViewer->Image = Image::FromFile(LeftFileName);
		if(RightFileName)
			rightPictureViewer->Image = Image::FromFile(RightFileName);
	}

	System::Void MainWindow::harrisFilterToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
/*
		if(System::Windows::Forms::DialogResult::OK == gaussWindow.ShowDialog()) {
			leftPictureViewer->Image = Harris(gcnew Bitmap(leftPictureViewer->Image), gaussWindow.Sigma);
		}
*/
		if(System::Windows::Forms::DialogResult::OK == harrisWindow.ShowDialog()) {
			// right
			Algorithm::Bitmap<float>* orig_right = toBitmap_float(gcnew Bitmap(rightPictureViewer->Image));
			Algorithm::Harris(*orig_right, (float)harrisWindow.Differential, (float)harrisWindow.Integral, (float)harrisWindow.HarrisParam, logCheckBox1->Checked);
			//rightPictureViewer->Image = toCLRBitmap(result_right);

			// left
			Algorithm::Bitmap<float>* orig_left = toBitmap_float(gcnew Bitmap(leftPictureViewer->Image));
			Algorithm::Harris(*orig_left, (float)harrisWindow.Differential, (float)harrisWindow.Integral, (float)harrisWindow.HarrisParam, logCheckBox2->Checked);
			//leftPictureViewer->Image = toCLRBitmap(result_left);

			processFeatures(orig_left, orig_right);

			delete orig_left;
			delete orig_right;
		}
	}
	
	ref class PointPair : public Object
	{
	public:
		Point^ p1;
		float f1;
		Point^ p2;
		float f2;
	};

	System::Void MainWindow::processFeatures(Algorithm::Bitmap<float>* left, Algorithm::Bitmap<float>* right)
	{
		if(!justfeaturesCheckbox->Checked)
		{
//			Dictionary<Point, PointPair^> found;
			SortedDictionary<float, KeyValuePair<Point, Point> > distmap;
			for(const Algorithm::Bitmap<float>::KeyPoint& keyp1 : left->keyPoints())
			{
				for(const Algorithm::Bitmap<float>::KeyPoint& keyp2 : right->keyPoints())
				{
					float siftdist2 = 0;
					for(size_t i=0; i<keyp1.fingerprint.size(); ++i)
					{
						siftdist2 += pow(keyp1.fingerprint[i]-keyp2.fingerprint[i],2);
					}
	/*				float siftdist = sqrt(siftdist2);

					Point kp1(keyp1.x, keyp1.y);
					PointPair^ pp;
					if(found.ContainsKey(kp1))
					{
						pp = found[kp1];
					}
					else
					{
						pp = gcnew PointPair();
						found.Add(kp1, pp);
					}
					if(pp->p1 == nullptr)
					{
						pp->p1 = gcnew Point(keyp2.x, keyp2.y);
						pp->f1 = siftdist;
					}
					else if(pp->p2 == nullptr)
					{
						pp->p2 = gcnew Point(keyp2.x, keyp2.y);
						pp->f2 = siftdist;
					}
					else
					{
						if(siftdist < pp->f1)
						{
							pp->f2 = pp->f1;
							pp->p2 = pp->p1;

							pp->f2 = siftdist;
							pp->p1 = gcnew Point(keyp2.x, keyp2.y);
						}
						else if(siftdist < pp->f2)
						{
							pp->f2 = siftdist;
							pp->p2 = gcnew Point(keyp2.x, keyp2.y);
						}
					}*/




					float localdist = (float)sqrt(pow(keyp1.x - keyp2.x,2) + pow(keyp1.y-keyp2.y, 2));
					float w = 0.25f;
					float dist = w*sqrt(siftdist2) + (1 - w) * localdist;
					if(dist < 1.75f)
						distmap[dist] = KeyValuePair<Point, Point>(Point(keyp1.x, keyp1.y), Point(keyp2.x, keyp2.y));
				}
			}
			int i=0;
			leftPictureViewer->clearfeatures();
			rightPictureViewer->clearfeatures();
			/*for(const Algorithm::Bitmap<float>::KeyPoint& keyp1 : left->keyPoints())
			{
				if(found[Point(keyp1.x, keyp1.y)] != nullptr)
				{
					PointPair^ pp = found[Point(keyp1.x, keyp1.y)];
					if(pp->p1 != nullptr)
					{
						if(pp->p2 != nullptr)
						{
							if(pp->f1/pp->f2 < 0.8)
							{
								leftPictureViewer->addfeature(keyp1.x, keyp1.y, 1.0f);
								rightPictureViewer->addfeature(pp->p1->X, pp->p1->Y, 1.0f);
							}
						}
						else
						{
							leftPictureViewer->addfeature(keyp1.x, keyp1.y, 1.0f);
							rightPictureViewer->addfeature(pp->p1->X, pp->p1->Y, 1.0f);
						}
					}
				}
			}*/
			for each (float f in distmap.Keys)
			{
				if(i++ >1000)
					break;
				leftPictureViewer->addfeature(distmap[f].Key.X, distmap[f].Key.Y, f);
				rightPictureViewer->addfeature(distmap[f].Value.X, distmap[f].Value.Y, f);
			}
		}
		else
		{
			leftPictureViewer->clearfeatures();
			rightPictureViewer->clearfeatures();
			for(const Algorithm::Bitmap<float>::Feature& keyp1 : left->features())
			{
				leftPictureViewer->addfeature(keyp1.x, keyp1.y, keyp1.f/5.0f);
			}
			for(const Algorithm::Bitmap<float>::Feature& keyp2 : right->features())
			{
				rightPictureViewer->addfeature(keyp2.x, keyp2.y, keyp2.f/5.0f);
			}
		}
	}

	System::Void MainWindow::hesseFilterToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
		if (System::Windows::Forms::DialogResult::OK == gaussWindow.ShowDialog())
		{
			Algorithm::Bitmap<float>* orig_right = toBitmap_float(gcnew Bitmap(rightPictureViewer->Image));
			/*Algorithm::Bitmap<float>* result_right = */Algorithm::Hesse(*orig_right, (float)gaussWindow.Sigma);
			//rightPictureViewer->Image = toCLRBitmap(result_right);
			//delete result_right;

			// left
			Algorithm::Bitmap<float>* orig_left = toBitmap_float(gcnew Bitmap(leftPictureViewer->Image));
			/*Algorithm::Bitmap<float>* result_left = */Algorithm::Hesse(*orig_left, (float)gaussWindow.Sigma);
			//leftPictureViewer->Image = toCLRBitmap(result_left);
			//delete result_left;

			processFeatures(orig_left, orig_right);

			delete orig_left;
			delete orig_right;
		}
	}

	System::Void MainWindow::previousButton_Click(System::Object^  sender, System::EventArgs^  e) {
		bool left = leftPictureViewer->prev();
		bool right = rightPictureViewer->prev();
		_ASSERT(left == right);

		//previousButton->Enabled = left;
	}

	System::Void MainWindow::nextButton_Click(System::Object^  sender, System::EventArgs^  e) {
		bool left = leftPictureViewer->next();
		bool right = rightPictureViewer->next();
		_ASSERT(left == right);

		//nextButton->Enabled = left;
	}
}